package org.biloxi.commands.impl;

import java.util.LinkedList;
import java.util.List;

import org.biloxi.commands.Command;
import org.biloxi.commands.CommandEventDispatcher;
import org.biloxi.commands.Filter;
import org.biloxi.commands.Listener;
import org.biloxi.model.GameState;

/**
 * CommandEvents can be useful for providing different filtered views of events resulting from a Command.
 * For example, many cards have "At the beginning of "-some-phase.  This could be implemented from a Command:
 * <code>
 * changePhase.do_(
 * 	new Filter(){
 * 		public boolean allow(ChangePhase.Results t) {
 * 			return t.phase == beginningOfWhatPhase;
 * 		}
 * 	},
 *  // logic
 * )
 * </code> 
 * 
 * This is incredibly verbose, and the meaning is lost.
 * 
 * PhaseEvents are examples of CommandEvents providing more clear and concise and card logic:
 * <code>
 * 	drawPhase.begins.do_(
 *   // logic
 *  );
 * </code>
 * 
 * to right  
 * 
 * @author Peter.WM.Wong@gmail.com
 *
 * @param <T> Command Event data type
 */
public class EventDispatcherImpl<O,R> implements CommandEventDispatcher<O,R>{
	protected class LFPair {
		public final Listener<O,R> list;
		public final Filter<R> filt;
		public LFPair(Listener<O,R> list, Filter<R> filt) {
			this.list = list;
			this.filt = filt;
		}
	}
	protected final List<LFPair>             _filteredHandlers = new LinkedList<LFPair>();
	protected final List<Listener<O,R>> _listeners  = new LinkedList<Listener<O,R>>();

	/**
	 * Registers an CommandListener which will be called when this Event occurs.   
	 * @param listener
	 */
	public final void do_(Listener<O,R> l){
		_listeners.add(l);
	}

	/**
	 * Registers a CommandListener with a Filter.  The Registered CommandListener
	 * will only be called if the Command's results are accepted by the Filter. 
	 * @param handler
	 * @param filter
	 */
	public final void do_(Listener<O,R> handler, Filter<R> filter){
		_filteredHandlers.add(new LFPair(handler,filter));
	}
	
	protected final R notifyListeners(Command<O,R> src, O options, R result, GameState gameState){
		// Run handlers
		for(Listener<O,R> h : _listeners)
			h.handle(src, options, result, gameState);
		
		// Run filtered handlers
		for(LFPair fh : _filteredHandlers)
			if(fh.filt.allow(result)) fh.list.handle(src, options, result, gameState);
		
		return result;
	}
	
}
